using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.ComponentModel;
using MimeCloud.Foundations.ErrorLogging;

namespace MimeCloud.FTPUtil.Components
{
    public class FileUploader : BackgroundWorker
    {
        public FileUploader()
        {
            this.WorkerReportsProgress = true;
            this.WorkerSupportsCancellation = true;
            this.DoWork += new DoWorkEventHandler(FileUploader_DoWork);
        }

        private void FileUploader_DoWork(object sender, DoWorkEventArgs e)
        {
            var args = e.Argument as FtpUploadArguments;
            var bwWorker = sender as BackgroundWorker;
            //set up result
            var result = new FtpUploadResult();

            //upload files
            int assetsRemaining = args.LocalFilepaths.Count + 1;
            foreach (string fileNameCurrent in args.LocalFilepaths)
            {
                assetsRemaining--;

                try
                {
                    //read file
                    FileStream re = new FileStream(fileNameCurrent, FileMode.Open,FileAccess.Read);

                    //define ftprequest
                    var ftpRequest =
                        WebRequest.Create(
                            MimeCloud.Business.Helpers.Web.WebPath.WebPathCombine(args.FtpPath,
                                                                        Path.
                                                                            GetFileName
                                                                            (fileNameCurrent)))
                        as FtpWebRequest;
                    ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
                    ftpRequest.ContentLength = re.Length;
                    ftpRequest.Credentials = args.FtpCredentials;
                    ftpRequest.KeepAlive = true;
                    ftpRequest.Timeout = 300000;
                    ftpRequest.Proxy = null;
                   
                    //write to request
                    int chunkSize = 31000;
                    bool bytesToUpload = true;
                    var requestStream = ftpRequest.GetRequestStream();
                    var progress = new FtpUploadProgressReport
                                       {AssetsRemaining = assetsRemaining, CurrentFileName = fileNameCurrent};
                    //buffer loop
                    while (bytesToUpload)
                    {
                        int currentChunkSize = chunkSize;
                        if (chunkSize >= re.Length - re.Position)
                        {
                            currentChunkSize = (int)re.Length - (int)re.Position;
                            bytesToUpload = false;
                        }

                        //upload chunk
                        byte[] buffer = new byte[currentChunkSize];
                        re.Read(buffer, 0, currentChunkSize);
                        requestStream.Write(buffer, 0, buffer.Length);

                        //report progress
                        progress.Message=String.Concat("Uploaded ",
                                          (int)re.Position / 1000,
                                          "k of ",
                                          (int)re.Length / 1000, "k");
                        bwWorker.ReportProgress(
                            ((int)
                             Math.Round(Decimal.Divide(re.Position, re.Length) * 100)),
                            progress
                            );
                    }
                    //finished sending data close request and file stream
                    requestStream.Close();
                    re.Close();

                    //get response
                    var response = ftpRequest.GetResponse() as FtpWebResponse;

                    //report response
                    progress.Message = String.Format("Upload complete. Server reports status code:{0} Description:{1}",response.StatusCode.ToString(),response.StatusDescription);
                    bwWorker.ReportProgress(100,progress);
                    //close reponse stream
                    response.Close();

                    //send result
                    result.SuccessfulUploads.Add(fileNameCurrent);

                }
                catch (Exception ex)
                {
                    result.Errors.Add(fileNameCurrent,ex);
                    ErrorHelper.LogError(new Exception("Could not FTP upload Video",
                                                       ex));
                }
            }
            e.Result = result;
        }

        public class FtpUploadResult
        {
            public FtpUploadResult()
            {
                Errors = new Dictionary<string, Exception>();
                SuccessfulUploads = new List<string>();
            }
            public List<String> SuccessfulUploads { get; set; }
            public Dictionary<string, Exception> Errors { get; set; }
        }

        public class FtpUploadProgressReport
        {
            public string CurrentFileName { get; set; }
            public int AssetsRemaining { get; set; }
            public string Message { get; set; }
        }

        public class FtpUploadArguments
        {
            public List<string> LocalFilepaths { get; set; }
            public ICredentials FtpCredentials { get; set; }
            public string FtpPath { get; set; }
        }

        private new void RunWorkerAsync()
        {

        }
        private new void RunWorkerAsync(object args)
        {

        }
        public void RunWorkerAsync(FtpUploadArguments args)
        {
            base.RunWorkerAsync(args);
        }
    }
}
